<?php


namespace App\Console\Commands\Lib;


use App\Models\Model;

/**
 * Trait Stats
 * @package App\Console\Commands\Lib
 * @property-read \Illuminate\Console\OutputStyle $output
 */
trait Stats
{
    /**
     * 入库的模型
     * @return Model
     */
    abstract protected function getModel();

    /**
     * 合并数据
     * @param array $rowsArray
     * @return array
     */
    protected function mergeData(...$rowsArray)
    {
        $data = [];
        foreach ($rowsArray as $rows) {
            foreach ($rows as $row) {
                $uniqueFields = array_only($row, $this->getModel()->getUniqueKeys());
                if (is_null(current($uniqueFields))) { // mysql聚合函数会返回一行NULL而非结果集，这里统一处理
                    continue;
                }
                $key = join('-', $uniqueFields);
                $data[$key] = isset($data[$key]) ? array_merge($data[$key], $row) : $row;
            }
        }
        return array_values($data);
    }

    /**
     * 入库单行数据，需要先合并数据
     * @param $datum
     * @param \Closure|null $closure 更新时的存储过程
     * @return bool
     */
    protected function saveDatum($datum, \Closure $closure = null)
    {
        $model = $this->getModel();
        $attributes = [];

        foreach ($model->getUniqueKeys() as $field) {
            $attributes[$field] = $datum[$field];
        }

        $datum = array_only($datum, $model->getFillable());
        $values = array_except($datum, array_keys($attributes));

        $affected = true;

        // 部分表没有id主键，所以没办法直接用Model::save()、Model::updateOrCreate()
        /** @noinspection PhpParamsInspection */
        $row = $model::where($attributes)->first();
        if ($row) {
            if ($row->fill($values)->getDirty()) {
                if ($closure) { // 类存储过程
                    $values = $closure($row, $values);
                }
                /** @noinspection PhpParamsInspection */
                $affected = $model::where($attributes)->update($values);
            }
        } else {
            $affected = $model::create($datum);
        }

        return $affected;
    }

    /**
     * 入库多行数据，需要先合并数据
     * @param $data
     * @param \Closure|null $closure 更新时的存储过程
     */
    protected function saveData($data, \Closure $closure = null)
    {
        if (!$data) {
            $this->info('没有数据');
            return;
        }

        $bar = $this->output->createProgressBar(count($data));
        foreach ($data as $datum) {
            if ($this->saveDatum($datum, $closure)) {
                $bar->advance();
            }
        }

        $this->info('');
    }
}
